import { locations } from "../../../gpu/locations";
export const Func = /*wgsl*/ `
fn clampedDot( x:vec3<f32>,  y:vec3<f32>)->f32
{
    return clamp(dot(x, y), 0.0, 1.0);
}
fn getIBLRadianceGGX( n:vec3<f32>,  v:vec3<f32>,  roughness:f32,  F0:vec3<f32>, specularWeight:f32)->vec3<f32>{
  var kk= vec3<f32>(0);
  #if ~{def.prefilterMap}
    var NdotV:f32 = clampedDot(n, v);
    var lod:f32 = roughness * f32(5 - 1);
    var reflection:vec3<f32> = -normalize(reflect(-v, n));
    var brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
    var f_ab:vec2<f32> = textureSample(brdfLUT, iblSampler,brdfSamplePoint).rg;
    var specularSample:vec4<f32> =textureSampleLevel(prefilterMap, iblSampler, reflection, lod);

    var specularLight:vec3<f32> = specularSample.rgb;
    var Fr:vec3<f32> = max(vec3(1.0 - roughness), F0) - F0;
    var k_S:vec3<f32> = F0 + Fr * pow(1.0 - NdotV, 5.0);
    var FssEss:vec3<f32> = k_S * f_ab.x + f_ab.y;

    kk= specularWeight * specularLight * FssEss;
  #endif
   return kk;
}
fn getIBLRadianceGGX1( n:vec3<f32>,  v:vec3<f32>,  roughness:f32,  specularWeight:f32,brdf:vec2<f32>,F:vec3<f32>)->vec3<f32>{
  var kk= vec3<f32>(0);
  #if ~{def.prefilterMap}
    var  MAX_REFLECTION_LOD = 4.0;
    var reflection:vec3<f32> = -normalize(reflect(-v, n));
    var prefilteredColor = textureSampleLevel(prefilterMap,iblSampler, reflection,roughness * MAX_REFLECTION_LOD).rgb; 
    kk= specularWeight*prefilteredColor * (F * brdf.x + brdf.y );
  #endif
   return kk;
}
fn getRangeAttenuation( range:f32,  distance:f32)->f32
{
 if (range <= 0.0)
    {
      return 1.0;
    }
    return max(min(1.0 - pow(distance / range, 4.0), 1.0), 0.0) / pow(distance, 2.0);
}
fn getSpotAttenuation( actualCos:f32, outerConeCos:f32,innerConeCos:f32)->f32
{
    if(actualCos>innerConeCos){
      return 1-smoothstep(innerConeCos,innerConeCos+0.001,actualCos);
    }
    return 1-smoothstep( innerConeCos,outerConeCos, actualCos);
}
// struct LightRay {
//   color:vec3<f32>,//0
//   t:f32,//type //3
//   position:vec3<f32>,//4
//   intensity:f32,//7
//   at:vec3<f32>,//8
//   range:f32,//11
//   e1:f32,//12   //面光源中e1,e2对应width,height  聚光灯中对应innerCos outerCos
//   e2:f32,//13
// }
fn getLighIntensity( light:LightRay,  pointToLight:vec3<f32>)->vec3<f32>
{
    var rangeAttenuation:f32 = 1.0;
    var spotAttenuation:f32 = 1.0;

    if (light.t == 1.0){//非方向光
      rangeAttenuation = getRangeAttenuation(light.range, length(pointToLight));
    }
    if (light.t == 2.0){//聚光灯
      var l1:vec3<f32> = normalize(light.position - light.at);//光源向量
      var angleCos:f32 = dot(l1,normalize(pointToLight));
      spotAttenuation = getSpotAttenuation(angleCos, light.e2, light.e1);
    }
    return rangeAttenuation * spotAttenuation * light.intensity * light.color;
}
fn F_Schlick(f0:vec3<f32>,f90:vec3<f32>, VdotH:f32)->vec3<f32>
{
  return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);
}
fn BRDF_lambertian(f0:vec3<f32>, f90:vec3f,diffuseColor:vec3<f32>, specularWeight:f32, VdotH:f32)->vec3<f32>
{
    return (1.0 - specularWeight * F_Schlick(f0, f90, VdotH)) * (diffuseColor / M_PI);
}
fn fresnelSchlick( cosTheta:f32,  F0:vec3<f32>)->vec3<f32>
{
    return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
fn fresnelSchlickRoughness(cosTheta:f32, F0:vec3<f32>, roughness:f32)->vec3<f32>
{
    return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}  
fn BRDF_lambertian1(diffuseColor:vec3<f32>, F:vec3<f32>,metallic:f32,specularWeight:f32)->vec3<f32>
{
  var kS =specularWeight* F;
  var kD = vec3(1.0) - kS;
  kD *= 1.0 - metallic;
   return kD * diffuseColor / M_PI;
}
fn V_GGX( NdotL:f32,NdotV:f32,alphaRoughness:f32)->f32
{
    var alphaRoughnessSq:f32 = alphaRoughness * alphaRoughness;
    var GGXV:f32 = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
    var GGXL:f32 = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
    var GGX:f32 = GGXV + GGXL;
    if (GGX > 0.0){
        return 0.5 / GGX;
    }
    return 0.0;
}
fn D_GGX( NdotH:f32,alphaRoughness:f32)->f32
{
    var alphaRoughnessSq:f32 = alphaRoughness * alphaRoughness;
    var f:f32 = (NdotH * NdotH) * (alphaRoughnessSq - 1.0) + 1.0;
    return alphaRoughnessSq / (M_PI * f * f);
}
fn BRDF_specularGGX( f0:vec3f,  f90:vec3f,  alphaRoughness:f32,specularWeight:f32, VdotH:f32,  NdotL:f32,  NdotV:f32,  NdotH:f32)->vec3<f32>
{
    var F = F_Schlick(f0, f90, VdotH);
    var Vis:f32 = V_GGX(NdotL, NdotV, alphaRoughness);
    var D:f32 = D_GGX(NdotH, alphaRoughness);

    return specularWeight * F * Vis * D;
}
fn DistributionGGX( NdotH:f32,  roughness:f32)->f32
{
    var a      = roughness*roughness;
    var a2     = a*a;
    var NdotH2 = NdotH*NdotH;
    var num   = a2;
    var denom = (NdotH2 * (a2 - 1.0) + 1.0);
    denom = M_PI * denom * denom;
    return num / denom;
}

fn GeometrySchlickGGX( NdotV:f32, roughness:f32)->f32
{
    var r = (roughness + 1.0);
    var k = (r*r) / 8.0;

    var num   = NdotV;
    var denom = NdotV * (1.0 - k) + k;

    return num / denom;
}
fn GeometrySmith(NdotV:f32,NdotL:f32, roughness:f32)->f32
{
    var ggx2  = GeometrySchlickGGX(NdotV, roughness);
    var ggx1  = GeometrySchlickGGX(NdotL, roughness);

    return ggx1 * ggx2;
}
fn BRDF_specularGGX1(F:vec3<f32>,NdotL:f32,NdotV:f32,NdotH:f32,roughness:f32,specularWeight:f32)->vec3<f32>
{
   var NDF = DistributionGGX(NdotH, roughness);        
   var G   = GeometrySmith(NdotV, NdotL, roughness);      
    var nominator    = NDF * G * F*specularWeight;
    var denominator = 4.0 * max(NdotV, 0.0) * max(NdotL, 0.0) + 0.0001; 
    return nominator / denominator;
}
fn cal_ambientLight(input:Input)->vec3<f32>{
  let out:vec3<f32>=ambientLight.color*ambientLight.intensity*materialInfo.baseColor;
  return out;
}
fn SRGBtoLinear( srgb:vec4<f32>)->vec4<f32> {
var linOut:vec3<f32> = pow(srgb.xyz, vec3<f32>(2.2));
return vec4<f32>(linOut, srgb.w);
}
fn getDiffuseLight( n:vec3<f32>)->vec3<f32>
{
    return textureSample(irradianceMap,iblSampler,n).rgb * environmenIntensity;
}
fn getIBLRadianceLambertian( n:vec3<f32>,  v:vec3<f32>, roughness:f32, diffuseColor:vec3<f32>, F0:vec3<f32>, specularWeight:f32)->vec3<f32>{
  var kk= vec3<f32>(0);
  #if ~{def.irradianceMap}
    var NdotV:f32 = clampedDot(n, v);
    var brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
    var f_ab:vec2<f32> = textureSample(brdfLUT, iblSampler,brdfSamplePoint).rg;
    var irradiance:vec3<f32> =getDiffuseLight(n);
    var Fr = max(vec3(1.0 - roughness), F0) - F0;
    var k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
    var FssEss = specularWeight * k_S * f_ab.x + f_ab.y;
  
    var Ems:f32 = (1.0 - (f_ab.x + f_ab.y));
    var F_avg:vec3<f32> = specularWeight * (F0 + (1.0 - F0) / 21.0);
    var FmsEms:vec3<f32>= Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
    var k_D:vec3<f32> = diffuseColor * (1.0 - FssEss + FmsEms); 
    kk= (FmsEms + k_D) * irradiance;
   #endif 
   return kk;
}
fn getIBLRadianceLambertian1( n:vec3<f32>,  diffuseColor:vec3<f32>,kD:vec3<f32>)->vec3<f32>{
  var kk= vec3<f32>(0);
  #if ~{def.irradianceMap}
    var irradiance:vec3<f32> =getDiffuseLight(n);
    var diffuse = irradiance * diffuseColor; 
    kk= kD * diffuse;
   #endif 
   return kk;
}
fn getSpecularSample( reflection:vec3<f32>,  lod:f32)->vec4<f32>
{
    return textureSampleLevel(prefilterMap, iblSampler, reflection, lod) * environmenIntensity;
}
#if ~{def.u_Anisotropy}
fn getIBLRadianceAnisotropy( n:vec3<f32>, v:vec3<f32>,  roughness:f32, anisotropy:f32, anisotropyDirection:vec3<f32>, specularWeight:f32,k_S:vec3<f32>,brdf:vec2<f32>)->vec3<f32>
{
    var tangentRoughness:f32 = mix(roughness, 1.0, anisotropy * anisotropy);
    var  anisotropicTangent:vec3<f32>  = cross(anisotropyDirection, v);
    var  anisotropicNormal:vec3<f32>   = cross(anisotropicTangent, anisotropyDirection);
    var bendFactor :f32         = 1.0 - anisotropy * (1.0 - roughness);
    var bendFactorPow4:f32      = bendFactor * bendFactor * bendFactor * bendFactor;
    var bentNormal:vec3<f32>          = normalize(mix(anisotropicNormal, n, bendFactorPow4));

    var lod:f32 = roughness * 4;
    var reflection:vec3<f32> = -normalize(reflect(-v, bentNormal));
    vec4 specularSample = getSpecularSample(reflection, lod);
    var specularLight = specularSample.rgb;
    var FssEss = k_S * brdf.x + brdf.y;

    return specularWeight * specularLight * FssEss;
}
#endif
#if ~{def.u_CharlieEnv}
 fn getSheenSample( reflection:vec3<f32>, lod:f32)->vec4<f32>
{
    return textureSampleLevel(u_CharlieEnv,u_CharlieEnvSampler,  reflection, lod) * environmenIntensity;
}
#endif
#if ~{def.u_CharlieLUT}
fn getIBLRadianceCharlie( n:vec3<f32>, v:vec3<f32>,sheenRoughness:f32, sheenColor:vec3<f32>)->vec3<f32>
{
    var NdotV:f32 = clampedDot(n, v);
    var lod:f32 = sheenRoughness * f32(4 - 1);
    var reflection:vec3<f32> = -normalize(reflect(-v, n));

    var brdfSamplePoint:vec2<f32> = clamp(vec2(NdotV, sheenRoughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
    var brdf:f32 = textureSample(u_CharlieLUT,u_CharlieLUTSampler,brdfSamplePoint).b;
    var sheenSample:vec4<f32> = getSheenSample(reflection, lod);

    var sheenLight:vec3<f32> = sheenSample.rgb;
    return sheenLight * sheenColor * brdf;
}
#endif
fn getVolumeTransmissionRay( n:vec3<f32>,  v:vec3<f32>,  thickness:f32,  ior:f32,  modelMatrix:mat4x4<f32>)->vec3<f32>
{
    var refractionVector:vec3<f32> = refract(-v, normalize(n), 1.0 / ior);

    var modelScale:vec3<f32>;
    modelScale.x = length(vec3(modelMatrix[0].xyz));
    modelScale.y = length(vec3(modelMatrix[1].xyz));
    modelScale.z = length(vec3(modelMatrix[2].xyz));

    return normalize(refractionVector) * thickness * modelScale;
}
fn applyVolumeAttenuation( radiance:vec3<f32>,  transmissionDistance:f32,  attenuationColor:vec3<f32>,attenuationDistance:f32)->vec3<f32>
{
    if (attenuationDistance == 0.0)
    {
        return radiance;
    }
    else
    {
        var attenuationCoefficient:vec3<f32> = -log(attenuationColor) / attenuationDistance;
        var transmittance:vec3<f32> = exp(-attenuationCoefficient * transmissionDistance); // Beer's law
        return transmittance * radiance;
    }
}
fn applyIorToRoughness( roughness:f32,  ior:f32)->f32
{
    return roughness * clamp(ior * 2.0 - 2.0, 0.0, 1.0);
}
#if ~{def.u_TransmissionFactor}
fn getTransmissionSample( fragCoord:vec2<f32>,  roughness:f32,  ior:f32)->vec3<f32>
{
    var framebufferLod:f32 = log2(f32(u_TransmissionFramebufferSize.x)) * applyIorToRoughness(roughness, ior);
    var transmittedLight:vec3<f32> = textureSampleLevel(u_TransmissionFramebuffer,u_TransmissionFramebufferSampler, fragCoord.xy, framebufferLod).rgb;
    return transmittedLight;
}
fn getIBLVolumeRefraction( n:vec3<f32>,  v:vec3<f32>,  perceptualRoughness:f32,  baseColor:vec3<f32>,  f0:vec3<f32>,  f90:vec3<f32>, position:vec3<f32>,  modelMatrix:mat4x4<f32>, viewMatrix:mat4x4<f32>,projMatrix:mat4x4<f32>,ior:f32,thickness:f32,attenuationColor:vec3<f32>,attenuationDistance:f32)->vec3<f32>
{
    var transmissionRay:vec3<f32> = getVolumeTransmissionRay(n, v, thickness, ior, modelMatrix);
    var refractedRayExit:vec3<f32> = position + transmissionRay;

    var ndcPos:vec4<f32> = projMatrix * viewMatrix * vec4(refractedRayExit, 1.0);
    var refractionCoords:vec2<f32> = ndcPos.xy / ndcPos.w;
    refractionCoords += 1.0;
    refractionCoords /= 2.0;

    var transmittedLight:vec3<f32> = getTransmissionSample(refractionCoords, perceptualRoughness, ior);

    var attenuatedColor:vec3<f32> = applyVolumeAttenuation(transmittedLight, length(transmissionRay), attenuationColor, attenuationDistance);

    // Sample GGX LUT to get the specular component.
    var NdotV:f32 = clampedDot(n, v);
    var brdfSamplePoint:vec2<f32> = clamp(vec2(NdotV, perceptualRoughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
    var brdf:vec2<f32> = textureSample(brdfLUT,iBLSampler brdfSamplePoint).rg;
    var specularColor:vec3<f32> = f0 * brdf.x + f90 * brdf.y;

    return (1.0 - specularColor) * attenuatedColor * baseColor;
}
#endif
#if ~{def.u_Anisotropy}
fn D_GGX_anisotropic(NdotH:f32,TdotH:f32,  BdotH:f32,  anisotropy:f32,  at:f32,  ab:f32)->f32
{
    var a2:f32 = at * ab;
    var f:vec3<f32> = vec3(ab * TdotH, at * BdotH, a2 * NdotH);
    var w2:f32 = a2 / dot(f, f);
    return a2 * w2 * w2 / M_PI;
}
fn V_GGX_anisotropic( NdotL:f32, NdotV:f32, BdotV:f32, TdotV:f32,TdotL:f32,BdotL:f32,at:f32,ab:f32)->f32
{
    var GGXV:f32 = NdotL * length(vec3(at * TdotV, ab * BdotV, NdotV));
    var GGXL:f32 = NdotV * length(vec3(at * TdotL, ab * BdotL, NdotL));
    var v:f32 = 0.5 / (GGXV + GGXL);
    return clamp(v, 0.0, 1.0);
}

fn BRDF_specularGGXAnisotropy(F:vec3<f32>, alphaRoughness:f32, anisotropy:f32, n:vec3<f32>, v:vec3<f32>, l:vec3<f32>, h:vec3<f32>, t:vec3<f32>,b:vec3<f32>)->vec3<f32>
{
    var at:f32 = mix(alphaRoughness, 1.0, anisotropy * anisotropy);
    var ab:f32 = clamp(alphaRoughness, 0.001, 1.0);

    var NdotL:f32 = clamp(dot(n, l), 0.0, 1.0);
    var NdotH:f32 = clamp(dot(n, h), 0.001, 1.0);
    var NdotV:f32 = dot(n, v);

    var V:f32 = V_GGX_anisotropic(NdotL, NdotV, dot(b, v), dot(t, v), dot(t, l), dot(b, l), at, ab);
    var D:f32 = D_GGX_anisotropic(NdotH, dot(t, h), dot(b, h), anisotropy, at, ab);

    return F * V * D;
}
#endif
#if ~{def.u_SheenColorFactor}
fn getPunctualRadianceSheen(sheenColor:vec3<f32>,sheenRoughness:f32, NdotL:f32,NdotV:f32,NdotH:f32)->vec3<f32>
{
    return NdotL * BRDF_specularSheen(sheenColor, sheenRoughness, NdotL, NdotV, NdotH);
}
fn D_Charlie(sheenRoughness1:f32, NdotH:f32)->f32
{
   var sheenRoughness = max(sheenRoughness1, 0.000001); //clamp (0,1]
   var alphaG = sheenRoughness * sheenRoughness;
   var invR = 1.0 / alphaG;
   var cos2h = NdotH * NdotH;
   var sin2h = 1.0 - cos2h;
    return (2.0 + invR) * pow(sin2h, invR * 0.5) / (2.0 * M_PI);
}
fn V_Sheen( NdotL:f32, NdotV:f32, sheenRoughness1:f32)->f32
{
    var sheenRoughness = max(sheenRoughness1, 0.000001); //clamp (0,1]
    var alphaG:f32 = sheenRoughness * sheenRoughness;

    return clamp(1.0 / ((1.0 + lambdaSheen(NdotV, alphaG) + lambdaSheen(NdotL, alphaG)) *
        (4.0 * NdotV * NdotL)), 0.0, 1.0);
}
fn lambdaSheen(cosTheta:f32, alphaG:f32)->f32
{
    if (abs(cosTheta) < 0.5)
    {
        return exp(lambdaSheenNumericHelper(cosTheta, alphaG));
    }
    else
    {
        return exp(2.0 * lambdaSheenNumericHelper(0.5, alphaG) - lambdaSheenNumericHelper(1.0 - cosTheta, alphaG));
    }
}
fn lambdaSheenNumericHelper( x:f32, alphaG:f32)->f32
{
    var oneMinusAlphaSq = (1.0 - alphaG) * (1.0 - alphaG);
    var a = mix(21.5473, 25.3245, oneMinusAlphaSq);
    var b = mix(3.82987, 3.32435, oneMinusAlphaSq);
    var c = mix(0.19823, 0.16801, oneMinusAlphaSq);
    var d = mix(-1.97760, -1.27393, oneMinusAlphaSq);
    var e = mix(-4.32054, -4.85967, oneMinusAlphaSq);
    return a / (1.0 + b * pow(x, c)) + d * x + e;
}
fn BRDF_specularSheen(sheenColor:vec3<f32>, sheenRoughness:f32, NdotL:f32, NdotV:f32, NdotH:f32)->vec3<f32>
{
    var sheenDistribution:f32 = D_Charlie(sheenRoughness, NdotH);
    var sheenVisibility:f32 = V_Sheen(NdotL, NdotV, sheenRoughness);
    return sheenColor * sheenDistribution * sheenVisibility;
}
fn albedoSheenScalingLUT(NdotV:f32, sheenRoughnessFactor:f32)->f32
{
    return textureSample(u_SheenELUT,u_SheenELUTSampler,vec2(NdotV, sheenRoughnessFactor)).r;
}
#endif
fn getPunctualRadianceClearCoat(clearcoatNormal:vec3<f32>,  v:vec3<f32>, l:vec3<f32>, h:vec3<f32>,  VdotH:f32,  f0:vec3<f32>,f90:vec3<f32>,  clearcoatRoughness:f32)->vec3<f32>
{
    var NdotL = clampedDot(clearcoatNormal, l);
    var NdotV = clampedDot(clearcoatNormal, v);
    var NdotH = clampedDot(clearcoatNormal, h);
    return NdotL * BRDF_specularGGX(f0, f90, clearcoatRoughness * clearcoatRoughness, 1.0, VdotH, NdotL, NdotV, NdotH);
}
fn getPunctualRadianceTransmission(normal:vec3<f32>,view:vec3<f32>,pointToLight:vec3<f32>, alphaRoughness:f32, f0:vec3<f32>,f90:vec3<f32>, baseColor:vec3<f32>,ior:f32)->vec3<f32>
{
  var transmissionRougness = applyIorToRoughness(alphaRoughness, ior);

  var n = normalize(normal);          
  var v = normalize(view);             
  var l = normalize(pointToLight);
  var l_mirror = normalize(l + 2.0*n*dot(-l, n));    
  var h = normalize(l_mirror + v);           

  var D = D_GGX(clamp(dot(n, h), 0.0, 1.0), transmissionRougness);
  var F = F_Schlick(f0, f90, clamp(dot(v, h), 0.0, 1.0));
  var Vis = V_GGX(clamp(dot(n, l_mirror), 0.0, 1.0), clamp(dot(n, v), 0.0, 1.0), transmissionRougness);

  // Transmission BTDF
  return (1.0 - F) * baseColor * D * Vis;
}
fn linearToSRGB( color:vec3<f32>,gamm:vec3<f32>)->vec3<f32> {
  return pow(color, vec3(1.0 / gamm.x,1.0 / gamm.y,1.0 / gamm.z));
}

`;